-
Notifications
You must be signed in to change notification settings - Fork 3
[2409] Csv Spawner Notification Bus #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: o3de-2409
Are you sure you want to change the base?
Conversation
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a lot of info passed in the bus calls. Verify if everything is needed. Consider creating a struct for this data.
Overall looks good!
Sure, it’s just a quick fix that I needed. A lot of the information is indeed unnecessary. I’ll refactor it soon. On further thought, it might be better to introduce some global |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks okay. I'm just curious if anything (beyond this PR, as it is obvious the implementation is not here) implements handlers for these two newly added functions? Or has the bus been created for some further work planned for the future?
In current state, we need some explicit logic to handle is terrain created (please look at #102). Exactly this functionality is needed in one project I'm working on. I would reconsider what information should be passed down in the buses. Right now notification is only needed. |
I've added:
|
Success = 0, ///< Operation succeeded. | ||
Fail = 1 << 0, ///< Generic failure. | ||
SpawnStopped = 1 << 1, ///< Spawning was stopped prematurely but not necessarily a failure. | ||
ErrorOccurred = 1 << 2, ///< An error occurred during spawning (potentially recoverable). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the bitshifts needed here? Typically, the bitshifts are used when multiple flags can happen at once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, I thought - spawn can still be successful even when some errors / issues occur. Like partialy some entites are spawned, some are spawned but not in desired place etc.
Rethining the problem... Could we include a behavioral context for LUA/ScriptCanvas in this PR? I can imagine a script reacting to spawned objects. |
Sure. I'll add also similar notify bus for Geo Json Spawner. |
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
9ce6d49
to
b30dda3
Compare
Signed-off-by: Wojciech Czerski <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked the code and I found some key issues that need your attention:
-
Unused Variable: The presence of an unused lambda capture relating to
tickets
is causing compilation issues. This needs to be either utilized or removed to get the code to compile. -
Dangling References: There are dangling references, which can lead to unexpected behavior.
-
Logical Issues: The conditional logic involving
totalTicket
andcompletedTickets
isn't set up correctly. This results in conditions that can never be met due to how the variables are managed. -
Missing Notifications: It's important to include notification calls to alert users about any failures.
I will be happy to check refined version
}; | ||
optionalArgs.m_completionCallback = | ||
[parentId, &spawnStatusCode]( | ||
[parentId, &spawnStatusCode, &broadcastSpawnInfo, &tickets, totalTickets, &completedTickets]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that the four references in question are currently dangling. This arises because local variables are being passed to the completion callback, which is executed after the SpawnEntities
function has ended. Once the function finishes, the references to the callback become invalid since the variables they point to no longer exist. It is important to address this issue to ensure the code functions as intended.
}; | ||
optionalArgs.m_completionCallback = | ||
[parentId, &spawnStatusCode]( | ||
[parentId, &spawnStatusCode, &broadcastSpawnInfo, &tickets, totalTickets, &completedTickets]( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reference to tickets
is not only dangling but also remains unused, which consequently interferes with building O3DE in the profile configuration.
completedTickets++; | ||
if (completedTickets == totalTickets) | ||
{ | ||
// Call CsvSpawner EBus notification - Finished | ||
CsvSpawnerNotificationBus::Broadcast(&CsvSpawnerInterface::OnEntitiesSpawnFinished, broadcastSpawnInfo, spawnStatusCode); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if we assume that completedTickets
is not a dangling reference, the current condition will not function as intended. The issue arises because totalTicket
is passed as a copy and incremented after the callback is defined. Consequently, completedTickets
will always be one greater than totalTickets
, resulting in the condition never being met. If you move the totalTickets++
before defining the callback, it would trigger with every callback. Therefore, it is advisable to explore a different approach to address this condition.
[parentId, &spawnStatusCode, &broadcastSpawnInfo, &tickets, totalTickets, &completedTickets]( | ||
[[maybe_unused]] AzFramework::EntitySpawnTicket::Id ticketId, AzFramework::SpawnableConstEntityContainerView view) | ||
{ | ||
if (view.empty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code within this if statement exhibits undefined behavior because spawnStatusCode
is a dangling reference. This may be the reason why you have not encountered any issues, as the code possibly has not executed as expected. Additionally, the code is missing a notification call to indicate a failure. A similar situation is present in the preinsertionCallback
.
Signed-off-by: Wojciech Czerski <[email protected]>
…lamdas Signed-off-by: Wojciech Czerski <[email protected]>
Signed-off-by: Wojciech Czerski <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked your fix and undefined behaviour are removed, which is nice. Good Job. Although there are some issues still present.
- there is invalid logic with decrementing of
pendingSpawns
- I think that notifcation bus definition is a bit wrong. We can add multiple CSVComponents on scene, so we should either send one notification when all components finished their jobs or each of them should send individual notification. Currently all notifications are broadcasted what is not optimal solution
Could you also explain why you decide to solve sending notification in the current way? I was thinking if wouldn't it be cleaner to define internal event, only in this Gem, which would be trigger everytime single completion callback is executed. It would take status, and cmopleted ticketId and would trigger the event on entityId of the componentOwner. Each component already has map of spawnedTickets. you would need to add unordered_set, which will gather all completedTickets inside mentioned event callback. If all tickets are completed, then you can send main notification that spawning is finished. I think it could potentially limit amount of data passed between threads and it might be a bit cleaner. But I don't want to force you to change the implementation right now. I would like to know your point of view on this problem.
|
||
#include "CsvSpawnerUtils.h" | ||
|
||
#include "AzCore/std/smart_ptr/make_shared.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#include "AzCore/std/smart_ptr/make_shared.h" | |
#include <AzCore/std/smart_ptr/make_shared.h> |
SpawnInfo broadcastSpawnInfo = | ||
SpawnInfo{ entitiesToSpawn, physicsSceneName, parentId }; // Spawn Info used in CsvSpawner EBus notify. | ||
SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - OnEntitiesSpawnFinished. | ||
// SpawnStatus spawnStatusCode = SpawnStatus::Success; // Spawn Status Code used for CsvSpawner EBus notify - |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recommend to remove this code if it is commented
virtual void OnEntitiesSpawnBegin(CsvSpawnerUtils::SpawnInfo m_spawnInfo) = 0; | ||
|
||
/** | ||
* @brief Called when entity spawning finishes. | ||
* @param m_spawnInfo Struct holding information about entities to be spawned. | ||
* @param m_statusCode Status code indicating success, failure and warnings of the spawn. | ||
*/ | ||
virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo& m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; | ||
virtual void OnEntitiesSpawnFinished(CsvSpawnerUtils::SpawnInfo m_spawnInfo, CsvSpawnerUtils::SpawnStatus m_statusCode) = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for removing those references?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that created notification methods are correct, but I've noticed that you set AddressPolicy
as Single
. We can have multiple CSVSpawner components on the scene. It means that we should be send notification either when all components finishes their jobs (you would need system component for that), or you can change this notification bus AddressPolicy
to ById
to allow each component to send their own notification. Then it would be client call to decide on which entity/component notification they want to connect with.
auto spawner = AZ::Interface<AzFramework::SpawnableEntitiesDefinition>::Get(); | ||
AZ_Assert(spawner, "Unable to get spawnable entities definition"); | ||
|
||
auto pendingSpawns = AZStd::make_shared<AZStd::atomic_int>(static_cast<int>(entitiesToSpawn.size())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside for loop through entitiesToSpawn
you have some conditions which cause iteration skip without calling spawning interface. This causes lack of decremention of pendingSpawns
what leads to situation where condition in line 349 is never met if as least one entity failed to spawn.
const AZ::Entity* root = *view.begin(); | ||
AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const AZ::Entity* root = *view.begin(); | |
AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); | |
const AZ::Entity* root = *view.begin(); | |
AZ_Assert(root, "Invalid root entity"); | |
AZ::TransformBus::Event(root->GetId(), &AZ::TransformBus::Events::SetParent, parentId); |
About:
This PR introduces a notification bus for the CSV spawner.
It provides the ability to trigger actions when entities are spawned and to gather information when the spawning process begins.
This is particularly useful when there is a need to react to the moment "when entities are spawned".